//////////////////////////////////////////////////////////////////////
//                                                                  //
//                                                                  //
//              Copyright (C), 2000  SEIKO EPSON Corp.              //
//              ALL RIGHTS RESERVED                                 //
//                                                                  //
//                                                                  //
//   file name : tanh.c                                             //
//                                                                  //
//   Revision history                                               //
//       00/02/10    first release                 M.Igarashi       //
//                                                                  //
//////////////////////////////////////////////////////////////////////

#include <math.h>
#include <smcvals.h>

// ALGORITHM
// 1.tanh(x)= sinh(x)/cosh(x)
//

//  the architecture of double floating point
//
//   0 1          11                  31 32                               63 bit
//   -----------------------------------------------------------------------
//  | |   exponent  |                    fraction                           |
//   -----------------------------------------------------------------------
//
//  |               |                   |                                   |
//  |    12 bits          20 bits       |             32 bits               |
//  |            lower word             |            higher word            |
//
//         bit    0         sign bit         (  1 bit  )
//              1 - 11      exponent part    ( 11 bits )
//             12 - 63      fraction part    ( 52 bits )
//
//
 
double tanh(double dfX){

	DBL_LNG       ckarg;       /* exchange the type to check the argument   */
	long lX;
	unsigned long ulLx,ulHx;
	double dfX2,dfRet;
	
	GETW_L(lX,dfX);		// get low
	GETW_H(ulHx,dfX);		// get high
	CLR_SIGN( dfX2, dfX );	// clear sign
	
	ulLx = lX&0x7fffffff;	// mask sign

	if( ulLx > 0x40428000 ||(ulLx == 0x40428000 && ulHx > 0x0 ) ){	// large val 
	/* check the argument */
		 ckarg._D = dfX;
		 CHECK_ARG( &ckarg );                            // check NaN
		 if ( ckarg.st._LL == P_INF.st._LL ) {      // x = Inf 
		    return( 1.0 );
		 } else if ( ckarg.st._LL == N_INF.st._LL ) {  // x = -Inf
		    return( - 1.0 );
		 }
	}
	dfRet = sinh(dfX2);
	dfRet /= cosh(dfX2);
	
	if((lX&0x80000000) == 0 ){				// positive
		return dfRet;
	}else{								// negative
		return -dfRet;
	}
	
}
